package com.zys.http.tool;


import cn.hutool.core.util.RandomUtil;

import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zys
 * @since 2025-08-10
 */
public class Placeholder {
    public static final Map<String, Function<String, Object>> SUPPLIER_MAP = new HashMap<>();

    static {
        SUPPLIER_MAP.put("{{$randomString}}", Placeholder::randomString);
        SUPPLIER_MAP.put("{{$randomUpperString}}", Placeholder::randomUpperString);
        SUPPLIER_MAP.put("{{$randomLowerString}}", Placeholder::randomLowerString);
        SUPPLIER_MAP.put("{{$randomInt}}", Placeholder::randomInt);
        SUPPLIER_MAP.put("{{$randomDouble}}", Placeholder::randomDouble);
        SUPPLIER_MAP.put("{{$randomLong}}", Placeholder::randomLong);
        SUPPLIER_MAP.put("{{$randomChinese}}", Placeholder::randomChinese);
        SUPPLIER_MAP.put("{{$uuid}}", s -> UUID.randomUUID().toString());
        SUPPLIER_MAP.put("{{$simpleUuid}}", s -> UUID.randomUUID().toString().replace("-",""));

        SUPPLIER_MAP.put("{{$timestamp}}", s -> System.currentTimeMillis());
        SUPPLIER_MAP.put("{{$year}}", s -> Calendar.getInstance().get(Calendar.YEAR));
        SUPPLIER_MAP.put("{{$month}}", s -> Calendar.getInstance().get(Calendar.MONTH));
        SUPPLIER_MAP.put("{{$day}}", s -> Calendar.getInstance().get(Calendar.DATE));
        SUPPLIER_MAP.put("{{$hour}}", s -> Calendar.getInstance().get(Calendar.HOUR));
        SUPPLIER_MAP.put("{{$minute}}", s -> Calendar.getInstance().get(Calendar.MINUTE));
        SUPPLIER_MAP.put("{{$second}}", s -> Calendar.getInstance().get(Calendar.SECOND));
        SUPPLIER_MAP.put("{{$date}}", s -> Calendar.getInstance().get(Calendar.DATE));
        SUPPLIER_MAP.put("{{$time}}", s -> Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE) + ":" + Calendar.getInstance().get(Calendar.SECOND));
    }

    public static Set<String> keywords() {
        return SUPPLIER_MAP.keySet();
    }

    public static Object replacePlaceholder(String key) {
        if (key == null || key.isEmpty()) {
            return key;
        }
        if (!isStartWithDoubleBrace(key) || !isEndWithDoubleBrace(key)) {
            return key;
        }
        if (key.startsWith("{{$random") && (key.contains("String") || key.contains("Chinese"))) {
            String number = findFirstNumber(key);
            String newKey = number == null ? key : key.replace(number, "");

            Function<String, Object> function = SUPPLIER_MAP.get(newKey);
            return function != null ? function.apply(number) : key;
        }

        if (key.startsWith("{{$random")) {
            String range = findRange(key);
            String newKey = range == null || range.isEmpty() ? key : key.replace(range, "");
            Function<String, Object> function = SUPPLIER_MAP.get(newKey);
            if (function == null) {
                return key;
            }

            return function.apply(range != null ? range.substring(1, range.length() - 1) : "");
        }

        return Optional.of(SUPPLIER_MAP.get(key).apply(key)).orElse(key);
    }

    private static boolean isStartWithDoubleBrace(String str) {
        return str != null && str.startsWith("{{");
    }

    private static boolean isEndWithDoubleBrace(String str) {
        return str != null && str.endsWith("}}");
    }

    private static String findRange(String input) {
        if (input == null || input.isEmpty()) {
            return null;
        }

        Matcher matcher = Pattern.compile("\\(-?\\d+(?:,-?\\d+){1,2}\\)").matcher(input);
        return matcher.find() ? matcher.group() : null;
    }

    private static String findFirstNumber(String input) {
        if (input == null || input.isEmpty()) {
            return null;
        }

        Matcher matcher = Pattern.compile("\\d+").matcher(input);
        return matcher.find() ? matcher.group() : null;
    }


    private static String randomString(String length) {
        try {
            int i = Integer.parseInt(length);
            i = Math.min(i, 200);
            return RandomUtil.randomString(i);
        } catch (Exception e) {
            return RandomUtil.randomString(8);
        }
    }

    private static String randomUpperString(String length) {
        try {
            int i = Integer.parseInt(length);
            i = Math.min(i, 200);
            return RandomUtil.randomStringUpper(i);
        } catch (Exception e) {
            return RandomUtil.randomStringUpper(8);
        }
    }

    private static String randomLowerString(String length) {
        try {
            int i = Integer.parseInt(length);
            i = Math.min(i, 200);
            return RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER_LOWER, i);
        } catch (Exception e) {
            return RandomUtil.randomString(RandomUtil.BASE_CHAR_NUMBER_LOWER, 8);
        }
    }

    private static Integer randomInt(String range) {
        try {
            String[] strings = range.split(",");
            int min = Integer.parseInt(strings[0]);
            int max = Integer.parseInt(strings[1]);
            return RandomUtil.randomInt(Math.min(min, max), Math.max(min, max));
        } catch (Exception e) {
            return RandomUtil.randomInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
        }
    }

    private static Double randomDouble(String range) {
        try {
            String[] strings = range.split(",");
            double min = Double.parseDouble(strings[0]);
            double max = Double.parseDouble(strings[1]);
            int scale = strings.length > 2 ? Integer.parseInt(strings[2]) : 2;
            return RandomUtil.randomDouble(Math.min(min, max), Math.max(min, max), scale, RoundingMode.HALF_UP);
        } catch (Exception e) {
            return RandomUtil.randomDouble(Double.MIN_VALUE, Double.MAX_VALUE);
        }
    }

    private static Long randomLong(String range) {
        try {
            String[] strings = range.split(",");
            long min = Long.parseLong(strings[0]);
            long max = Long.parseLong(strings[1]);
            return RandomUtil.randomLong(Math.min(min, max), Math.max(min, max));
        } catch (Exception e) {
            return RandomUtil.randomLong(Long.MIN_VALUE, Long.MAX_VALUE);
        }
    }

    private static String randomChinese(String length) {
        int i;
        try {
            i = Integer.parseInt(length);
        } catch (Exception e) {
            i = 3;
        }
        StringBuilder chinese = new StringBuilder();
        for (int j = 0; j < i; j++) {
            chinese.append(RandomUtil.randomChinese());
        }
        return chinese.toString();
    }
}
